package com.offcn.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.offcn.common.entity.Page;
import com.offcn.common.entity.Result;
import com.offcn.search.pojo.SkuInfo;
import com.offcn.search.mapper.SeachMapper;
import com.offcn.search.service.SearchService;
import com.offcn.sellergoods.feign.ItemFeign;
import com.offcn.sellergoods.pojo.Item;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ItemFeign itemFeign;

    @Autowired
    private SeachMapper seachMapper;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 触发实现远程调用 并向es导入数据
     */
    @Override
    public void importData() {
        //远程调用
        Result<List<Item>> result = itemFeign.status("1");
        List<Item> list = result.getData();
        for (Item item : list) {
            System.out.println(item);
        }

        //深克隆  --利用json串来回转换
        String json = JSON.toJSONString(list);
        List<SkuInfo> skuInfos = JSON.parseArray(json, SkuInfo.class);
        for (SkuInfo info : skuInfos) {
            String spec = info.getSpec();
            Map map = JSON.parseObject(spec, Map.class);
            info.setSpecMap(map);
        }

        //导入数据
        seachMapper.saveAll(skuInfos);
    }

    /**
     * 前端页面向此处发来查询请求,并没有带关键字[搜索功能]
     *
     * @param searchMap
     * @return
     */
    @Override
    public Map<String, Object> search(Map<String, String> searchMap) {
        if (searchMap == null) {
            searchMap = new HashMap<>();
        }

        if (searchMap.get("keywords") == null) {
            //设置默认条件
            searchMap.put("keywords", "手机");
        }

        Map<String, Object> map = new HashMap<>();

        //构造者对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        //////////////////////////////高亮效果设置///////////////////////////
        //指定要标价高亮的字段
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("title"));
        nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<span style='color:red;'>").postTags("</span>"));


        ////////////////////////////////分组统计操作/////////////////////////
        //品牌分组
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandGroup").field("brand"));
        //分类分组
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategoryGroup").field("category"));
        //规格分组
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecGroup").field("spec.keyword"));


        /////////////////////////////////////*******封装查询条件*********////////////////////////////////////////
        /**
         * QueryBuilders.termQuery() 不对条件进行分词
         * QueryBuilders.matchAllQuery()  查询所有 没有条件
         * QueryBuilders.matchQuery()   根据条件查询  条件值分词
         * QueryBuilders.multiMatchQuery()  多字段使用同一个值查询
         */

        //不同字段使用用同一值查询

        nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(searchMap.get("keywords"), "title", "brand", "category"));

        //////////////////////////////////////其他条件/////////////////////////
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        ////////////////////////区间查询---价格区间/////////////////////////////
        if (!StringUtils.isEmpty(searchMap.get("price"))) {
            // 0-100  100-1000  3000-*
            String value = searchMap.get("price");
            String[] split = value.split("-");
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(split[0]));
            if (!"*".equals(split[1])) {
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lt(split[1]));
            }
        }
        //////////////////////品牌、分类、规格多条件查询/////////////////////////

        //品牌
        if (!StringUtils.isEmpty(searchMap.get("brand"))) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("brand", searchMap.get("brand")));
        }
        if (!StringUtils.isEmpty(searchMap.get("category"))) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("category", searchMap.get("category")));
        }
        //规格
        for (String key : searchMap.keySet()) {
            if (key.startsWith("spec_")) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", searchMap.get(key)));
            }
        }

        nativeSearchQueryBuilder.withFilter(boolQueryBuilder);

        //////////////////////////////////////分页实现/////////////////////////////
        //默认当前页
        int pageNo = 1;
        if (!StringUtils.isEmpty(searchMap.get("pageNo"))) {
            pageNo = Integer.parseInt(searchMap.get("pageNo"));
        }

        //默认当前页显示数据
        int pageSize = 10;
        if (!StringUtils.isEmpty(searchMap.get("pageSize"))) {
            pageSize = Integer.parseInt(searchMap.get("pageSize"));
        }

        //es中页码从0开始
        nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNo - 1, pageSize));

        ///////////////////////////////排序实现///////////////////////////////////
        if(!StringUtils.isEmpty(searchMap.get("sortFeild")) && !StringUtils.isEmpty(searchMap.get("sortType"))){
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(searchMap.get("sortFeild")).order("desc".equalsIgnoreCase(searchMap.get("sortType")) ? SortOrder.DESC : SortOrder.ASC));
        }

        //查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();

        //////////////////////////////////发送请求，获取响应///////////////////////
        //发送查询请求给es es给回响应
        SearchHits<SkuInfo> searchHits = elasticsearchRestTemplate.search(query, SkuInfo.class);
        //分页
        SearchPage<SkuInfo> searchPage = SearchHitSupport.searchPageFor(searchHits, query.getPageable());

        ////////////////////////////////////处理响应//////////////////////////////
        //替换skuinfo对象中title字段的值
        for (SearchHit<SkuInfo> hit : searchHits) {
            //获取高亮的内容
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            List<String> list = highlightFields.get("title");
            SkuInfo skuInfo = hit.getContent();
            skuInfo.setTitle(list != null && list.size() > 0 ? list.get(0) : skuInfo.getTitle());
        }

        //获取总行数
        long totalRows = searchHits.getTotalHits();
        // 获取总页数
        int totalPages = searchPage.getTotalPages();
        // 获取当前数据
        List<SkuInfo> list = new ArrayList<>();
        List<SearchHit<SkuInfo>> contents = searchPage.getContent();
        for (SearchHit<SkuInfo> hit : contents) {
            SkuInfo skuInfo = hit.getContent();
            list.add(skuInfo);
        }
        //获取到品牌分组
        Terms brandTerms = searchHits.getAggregations().get("skuBrandGroup");
        List<String> brandList = new ArrayList<>();
        for (Terms.Bucket bucket : brandTerms.getBuckets()) {
            //获取所品牌的名字
            brandList.add(bucket.getKeyAsString());
        }

        //获取到分类分组
        Terms categoryTerms = searchHits.getAggregations().get("skuCategoryGroup");
        ArrayList<String> categoryList = new ArrayList<>();
        for (Terms.Bucket bucket : categoryTerms.getBuckets()) {
            //获取所有分类的名字
            categoryList.add(bucket.getKeyAsString());
        }

        //获取规格分组
        Terms specTerms = searchHits.getAggregations().get("skuSpecGroup");
        //map{'机身内存'===== set[16G,32G...],'网络'=== set[4G,5G...],....}
        Map<String, Set<String>> specMap = new HashMap<>();
        HashSet<String> keySet = new HashSet<>();
        for (Terms.Bucket bucket : specTerms.getBuckets()) {
            //{"机身内存":"128G","网络":"电信4G"}
            String keyAsString = bucket.getKeyAsString();
            keySet.add(keyAsString);
        }

        //{"机身内存":"128G","网络":"电信4G"}
        for (String str : keySet) {
            Map<String, String> m = JSON.parseObject(str, Map.class);
            //机身内存   网络
            for (String key : m.keySet()) {
                //128G  电信4G
                String value = m.get(key);
                Set<String> spcValue = specMap.get(key);
                if (spcValue == null) {
                    spcValue = new HashSet<>();
                }
                spcValue.add(value);
                specMap.put(key, spcValue);
            }
        }

        Page page = new Page<>(totalRows,pageNo,pageSize);
        ////////////////////////////////封装/////////////////////////////
        //当前页数据
        map.put("rows", list);
        //总行数
        map.put("total", totalRows);
        //总页数
        map.put("totalPages", totalPages);
        //品牌的分组
        map.put("brandList", brandList);
        //分类的分组
        map.put("categoryList", categoryList);
        //分类分组
        map.put("specMap", specMap);
        //分页
        map.put("page", page);
        return map;
    }
}
